package com.simonall.print;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import cn.hutool.core.util.StrUtil;

/**
 * 打印服务适配器
 * 
 * @author simonall
 */
@SuppressWarnings({ "all" })
public class PrintServiceAdapter {

	public static PrintHandler adapter(String fileName) {
		List<Class> childrenClazz = getChildClass(PrintHandler.class);
		for (Class clazz : childrenClazz) {
			try {
				PrintHandler handler = (PrintHandler) clazz.newInstance();
				if (Stream.of(handler.handleType()).anyMatch(t -> t.name().equalsIgnoreCase(fileName))) {
					return handler;
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * 查找指定继承、实现的子类
	 * 
	 * @param parentClass 父类
	 * @return
	 */
	private static List<Class> getChildClass(Class parentClass) {
		String packageName = parentClass.getPackage().getName();
		return getPackageClass(packageName).stream().filter(clazz -> {
			if (parentClass.isAssignableFrom(clazz) && !parentClass.equals(clazz)) {
				return true;
			}
			return false;
		}).collect(Collectors.toList());
	}

	/**
	 * 查询同包内所有子类
	 * 
	 * @param parentClass 父类
	 * @return
	 */
	private static List<Class> getPackageClass(String packageName) {
		ClassLoader loader = PrintServiceAdapter.class.getClassLoader();
		String path = packageName.replace(StrUtil.DOT, StrUtil.SLASH);
		Enumeration<URL> resources = null;
		try {
			resources = loader.getResources(path);
		} catch (IOException e) {
			e.printStackTrace();
		}
		List<File> fileList = new ArrayList<File>();
		while (resources.hasMoreElements()) {
			URL resource = resources.nextElement();
			fileList.add(new File(resource.getFile()));
		}
		ArrayList<Class> classList = new ArrayList<Class>();
		for (File file : fileList) {
			classList.addAll(findClass(file, packageName));
		}
		return classList;
	}

	/**
	 * 递归查找字节码
	 * 
	 * @param file        文件
	 * @param packageName 包
	 * @return
	 */
	private static List<Class> findClass(File file, String packageName) {
		List<Class> classList = new ArrayList<Class>();
		if (!file.exists()) {
			return classList;
		}
		File[] fileArray = file.listFiles();
		for (File subFile : fileArray) {
			if (subFile.isDirectory()) {
				assert !file.getName().contains(StrUtil.DOT);
				classList.addAll(findClass(subFile, packageName + StrUtil.DOT + subFile.getName()));
			} else if (subFile.getName().endsWith(".class")) {
				try {
					classList.add(Class.forName(packageName + StrUtil.DOT + subFile.getName().split(".class")[0]));
				} catch (ClassNotFoundException e) {
					e.printStackTrace();
				}
			}
		}
		return classList;
	}

}
